package com.zcf.controller;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.security.KeyStore;
import java.text.DecimalFormat;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.zcf.common.yunos.aliyun.MessageType;
import com.zcf.common.yunos.aliyun.SendMessage;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zcf.common.json.Body;
import com.zcf.common.utils.DateUtils;
import com.zcf.mapper.LogMapper;
import com.zcf.mapper.OrderMapper;
import com.zcf.mapper.OrderinfoMapper;
import com.zcf.mapper.UserMapper;
import com.zcf.pay.WXpay.ConstantUtil;
import com.zcf.pay.WXpay.Md5Util;
import com.zcf.pay.WXpay.PrepayIdRequestHandler;
import com.zcf.pay.WXpay.RequestHandler;
import com.zcf.pay.WXpay.TenpayUtil;
import com.zcf.pay.WXpay.WXUtil;
import com.zcf.pay.WXpay.WxNotifyParam;
import com.zcf.pay.WXpay.XMLUtil;
import com.zcf.pojo.Dining;
import com.zcf.pojo.Freight;
import com.zcf.pojo.Log;
import com.zcf.pojo.MyCoupon;
import com.zcf.pojo.Orderinfo;
import com.zcf.pojo.Orders;
import com.zcf.pojo.Percentage;
import com.zcf.pojo.Riding;
import com.zcf.pojo.Subordinate;
import com.zcf.pojo.User;
import com.zcf.utils.AESUtil;
import com.zcf.utils.AppPush;
import com.zcf.utils.Hutool;
import com.zcf.vo.out.RefundVo;

@Controller
@RequestMapping("/orderslp")
public class WXpayController {
	@Autowired
	OrderinfoMapper ordersMapper;
	@Autowired
	UserMapper userMapper;
	@Autowired
	LogMapper logMapper;

	private static final Logger logger = LoggerFactory.getLogger(WXpayController.class);

	/**
	 * 初始化微信支付
	 *
	 * // * @param request // * @param response // * @param orderId // * @return
	 */
	// @RequestMapping("/pay/wx")
	// @ResponseBody
	public WxNotifyParam initWx(HttpServletRequest request, HttpServletResponse response, Orderinfo orders) {
		// Map<String, Object> map = new HashMap<String, Object>();
		// 获取生成预支付订单的请求类
		PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);
//		Integer sum = Integer.parseInt(orders.getTotalMoney()) - Integer.parseInt(orders.getCouponMoney());
		Double money = orders.getTotalMoney();
		new DecimalFormat("#.00").format(money);
		String totalFee = String.valueOf((int) (money * 100));// 微信支付是
		// 分--* 100
		// 上线后，将此代码放开
		prepayReqHandler.setParameter("appid", ConstantUtil.APP_ID);
		prepayReqHandler.setParameter("body", ConstantUtil.BODY);
		prepayReqHandler.setParameter("mch_id", ConstantUtil.MCH_ID);
		String nonce_str = WXUtil.getNonceStr();
		prepayReqHandler.setParameter("nonce_str", nonce_str);
		prepayReqHandler.setParameter("notify_url", ConstantUtil.NOTIFY_URL);
		// String out_trade_no = userOrder.getOrderNo();
//		String out_trade_no = orders.getOrderNumber() + "";
		prepayReqHandler.setParameter("out_trade_no", orders.getOrderNumber());
		// request.getRemoteAddr()
		// "14.23.150.211"
		prepayReqHandler.setParameter("spbill_create_ip", "47.104.236.119");
//		prepayReqHandler.setParameter("spbill_create_ip", "47.100.110.119");
		String timestamp = WXUtil.getTimeStamp();
		prepayReqHandler.setParameter("time_start", timestamp);
		// logger.info("金额" + totalFee);
		prepayReqHandler.setParameter("total_fee", totalFee);
		prepayReqHandler.setParameter("trade_type", "APP");
		/**
		 * 注意签名（sign）的生成方式，具体见官方文档（传参都要参与生成签名，且参数名按照字典序排序，最后接上APP_KEY,转化成大写）
		 */
		prepayReqHandler.setParameter("sign", prepayReqHandler.createMD5Sign());
		prepayReqHandler.setGateUrl(ConstantUtil.GATEURL);
		String prepayid;
		WxNotifyParam param = new WxNotifyParam();
		try {
			prepayid = prepayReqHandler.sendPrepay();
			// 若获取prepayid成功，将相关信息返回客户端
			if (prepayid != null && !prepayid.equals("")) {
				String signs = "appid=" + ConstantUtil.APP_ID + "&noncestr=" + nonce_str
						+ "&package=Sign=WXPay&partnerid=" + ConstantUtil.PARTNER_ID + "&prepayid=" + prepayid
						+ "&timestamp=" + timestamp + "&key=" + ConstantUtil.APP_KEY;
				/**
				 * 签名方式与上面类似
				 */
				param.setPrepayId(prepayid);
				param.setSign(Md5Util.MD5Encode(signs, "utf8").toUpperCase());
				param.setAppId(ConstantUtil.APP_ID);
				// 等于请求prepayId时的time_start
				param.setTimeStamp(timestamp);
				// 与请求prepayId时值一致
				param.setNonceStr(nonce_str);
				// 固定常量
				param.setPackages("Sign=WXPay");
				param.setPartnerId(ConstantUtil.PARTNER_ID);
				logger.info("-----------》创建微信订单成功: " + param);
				logger.info("-----------》获取微信订单Id成功: " + orders.getOrderNumber());
			} else {
				return null;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			return null;
		}
		return param;
	}

	/**
	 * 接收微信支付回调通知
	 *
	 * @param request
	 * @param response
	 * @throws Exception
	 */

	@RequestMapping(value = "/wx/notify_url", method = RequestMethod.POST)
	public void getTenPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>进入微信回调方法");
		PrintWriter writer = response.getWriter();
		InputStream inStream = request.getInputStream();
		ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = inStream.read(buffer)) != -1) {
			outSteam.write(buffer, 0, len);
		}
		outSteam.close();
		inStream.close();
		String result = new String(outSteam.toByteArray(), "utf-8");
		logger.info("微信回调支付通知结果：" + result);
		Map<String, String> map = null;
		try {
			/**
			 * 解析微信通知返回的信息
			 */
			map = XMLUtil.doXMLParse(result);
		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		logger.info("- - - - - - - - -");
		logger.info("= = = = = = = = =:" + map);
		// 若充值成功，则告知微信服务器收到通知
		if (map.get("return_code").equals("SUCCESS")) {
			if (map.get("result_code").equals("SUCCESS")) {
				logger.info("微信充值会员体系成功！");
				String out_trade_no = map.get("out_trade_no");
				Orderinfo orders1 = new Orderinfo();
				EntityWrapper<Orderinfo> entityWrapper = new EntityWrapper<>();
				entityWrapper.eq("order_number", out_trade_no);
				orders1 = orders1.selectOne(entityWrapper);
				if (orders1 != null && orders1.getStatus() == 0) {
					Dining dining = new Dining();
					dining = dining.selectById(orders1.getDinId());
					User users = new User();
					users = users.selectById(dining.getUserId());
					if (users != null) {
						SendMessage.send(MessageType.GETORDER, dining.getPhone(),"1");
						AppPush.pushinfo(users.getCid());
					}

					orders1.setCompletionTime(Hutool.parseDateToString());// 回调成功时 执行
					orders1.setPayment("1");// 支付方式
					orders1.setStatus(1);// 已付款 或者 待收货
					orders1.setDinStatus(0);
					orders1.updateById();

//					if (orders1.getMyId() != null && !orders1.getMyId().equals("")) {
//						MyCoupon myCoupon = new MyCoupon();
//						myCoupon.setId(orders1.getMyId());
//						myCoupon.deleteById();
//					}

					User user = new User();
					EntityWrapper<User> ew = new EntityWrapper<>();
					ew.eq("id", orders1.getUserId());
					user = user.selectOne(ew);
					// 添加日志
					Log log = new Log();
					log.setAddtime(DateUtils.formatTimeNow());
					log.setLogDesc("微信支付");
					log.setLogType(2);
					double sum = (orders1.getTotalMoney()) - Double.parseDouble(orders1.getCouponMoney());
					log.setLogName(user.getName() + "消费了" + sum + "元");
					log.setLogId(Hutool.getId());
					log.setUserId(user.getId());
					log.setOrderId(out_trade_no);
					log.setMoneys(sum + "");
					logMapper.insert(log);
				}
			} else {
				logger.error("微信支付回调失败");
			}
		}
		logger.error("微信支付回调失败");
	}

//	@PostMapping("/doRefund")
//	@ResponseBody
	public Body refundOrder(HttpServletRequest request, HttpServletResponse response, Orderinfo order, String price) {

		// 商户相关资料
		String appid = ConstantUtil.APP_ID;// 公众号appid
		String appsecret = ConstantUtil.APP_SECRET;// 公众号秘钥
		String partner = ConstantUtil.PARTNER_ID;// 商户号
		String partnerkey = ConstantUtil.PARTNER_key;// 商户API秘钥
		// 用于获取随机数
		String currTime = TenpayUtil.getCurrTime();// 获取当前时间
		String strTime = currTime.substring(8, currTime.length());// 8位日期
		String strRandom = TenpayUtil.buildRandom(4) + "";// 四位随机数
		String strReq = strTime + strRandom;// 10位序列号,可以自行调整
		// 设置随机字符串
		String nonce_str = strReq;
		// 设置商户退款单号
		Integer randomNumber = new Random().nextInt(900) + 100;
		String orderIncrementId = Hutool.getTime() + randomNumber;
		String out_trade_no = order.getOrderInfoId() + "";
		// 总金额以分为单位，不带小数点
		int total_fee = (int) (order.getTotalMoney().doubleValue() * 100);
		// 商户号
		String mch_id = partner;
		// 退款回调地址
		String notify_url = "http://47.104.236.119/paotui/orderslp/refundCallback";
//		String notify_url = "http://172.16.1.109:8080/paotui/orderslp/refundCallback";
		int refund_fee = (int) (Double.parseDouble(price) * 100);
		// 创建hashmap(用户获得签名)
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("appid", appid);
		packageParams.put("mch_id", mch_id);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("out_trade_no", out_trade_no);
		packageParams.put("out_refund_no", orderIncrementId);
		packageParams.put("total_fee", total_fee + "");
		packageParams.put("refund_fee", refund_fee + "");

		packageParams.put("notify_url", notify_url);

		RequestHandler reqHandler = new RequestHandler(request, response);
		reqHandler.init(appid, appsecret, partnerkey);
		String sign = reqHandler.createSign(packageParams);

		String xml = "<xml>" + "<appid>" + appid + "</appid>" + "<mch_id>" + mch_id + "</mch_id>" + "<nonce_str>"
				+ nonce_str + "</nonce_str>" + "<sign>" + sign + "</sign>" + "<out_refund_no>" + orderIncrementId
				+ "</out_refund_no>" + "<out_trade_no>" + out_trade_no + "</out_trade_no>" + "<refund_fee>" + refund_fee
				+ "</refund_fee>" + "<total_fee>" + total_fee + "</total_fee>" + "<notify_url>" + notify_url
				+ "</notify_url>" + "</xml>";

		RefundVo rv = new RefundVo();
		try {
			// 发送请求(POST)(获得数据包ID)(这有个注意的地方 如果不转码成ISO8859-1则会告诉你body不是UTF8编码
			// 就算你改成UTF8编码也一样不好使 所以修改成ISO8859-1)
			System.out.println("xml>>>" + doRefund(ConstantUtil.REFUND_URL, new String(xml.getBytes(), "ISO8859-1")));
			Map<String, String> map = XMLUtil
					.doXMLParse(doRefund(ConstantUtil.REFUND_URL, new String(xml.getBytes(), "ISO8859-1")));
			// 应该创建 退款表数据
			if (map != null

					&& (StringUtils.isNotBlank(map.get("return_code")) && "SUCCESS".equals(map.get("return_code")))) {
				if (StringUtils.isBlank(map.get("err_code_des"))) {
					// 接口调用成功 执行操作逻辑 返回成功状态码给前台
					return Body.newInstance("成功");
				} else {
					// resultJson.put("returnCode", "error");
					// resultJson.put("err_code_des", map.get("err_code_des"));
					rv.setReturnCode("error");
					rv.setErrCodeDes(map.get("err_code_des"));
				}
			} else {
				// resultJson.put("returnCode", map.get("return_code"));
				// resultJson.put("err_code_des", map.get("err_code_des"));
				rv.setReturnCode(map.get("return_code"));
				rv.setErrCodeDes(map.get("err_code_des"));
			}
		} catch (UnsupportedEncodingException e) {
			logger.info("微信 退款 异常：" + e.getMessage());
			e.printStackTrace();
		} catch (Exception e) {
			logger.info("微信 退款 异常：" + e.getMessage());
			e.printStackTrace();
		}
		logger.info("微信 退款 失败");
		System.out.println(rv.getErrCodeDes());
		return Body.newInstance(501, "微信 退款 失败" + rv);
	}

	private String doRefund(String url, String data) throws Exception {
		/**
		 * 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
		 */

		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		// 证书存放路径
		String path = "/home/wwwroot/web/oulWV_certificate/";
//		String path = "C:/oulWV_certificate/";

		FileInputStream instream = new FileInputStream(path + "apiclient_cert.p12");// P12文件目录

		try {
			/**
			 * 此处要改
			 */
			keyStore.load(instream, ConstantUtil.MCH_ID.toCharArray());// 这里写密码..默认是你的MCHID
		} finally {
			instream.close();
		}

		// Trust own CA and all self-signed certs
		/**
		 * 此处要改
		 */
		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, ConstantUtil.MCH_ID.toCharArray())// 这里也是写密码的
				.build();
		// Allow TLSv1 protocol only
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
				SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
			HttpPost httpost = new HttpPost(url); // 设置响应头信息
			httpost.addHeader("Connection", "keep-alive");
			httpost.addHeader("Accept", "*/*");
			httpost.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
			httpost.addHeader("Host", "api.mch.weixin.qq.com");
			httpost.addHeader("X-Requested-With", "XMLHttpRequest");
			httpost.addHeader("Cache-Control", "max-age=0");
			httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
			httpost.setEntity(new StringEntity(data, "UTF-8"));
			CloseableHttpResponse response = httpclient.execute(httpost);
			try {
				HttpEntity entity = response.getEntity();

				String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
				EntityUtils.consume(entity);
				System.out.println(">>>>>>>" + jsonStr);
				return jsonStr;
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
	}

	@PostMapping("/refundCallback")
	@ResponseBody
	public void refundCallback(HttpServletRequest request, HttpServletResponse response) {
		logger.info("退款 微信回调接口方法 start");
		String inputLine = "";
		String notityXml = "";
		try {
			while ((inputLine = request.getReader().readLine()) != null) {
				notityXml += inputLine;
			}
			// 关闭流
			request.getReader().close();
			logger.info("退款 微信回调内容信息：" + notityXml);
			// 解析成Map
			Map<String, String> map = XMLUtil.doXMLParse(notityXml);
			// 判断 退款是否成功
			if ("SUCCESS".equals(map.get("return_code"))) {
				logger.info("退款 微信回调返回是否退款成功：是");
				// 获得 返回的商户订单号
				System.out.println(map.get("req_info"));
				String passMap = AESUtil.decryptData(map.get("req_info"));
				// 拿到解密信息
				map = XMLUtil.doXMLParse(passMap);
				// 拿到解密后的订单号
				String outTradeNo = map.get("out_trade_no");

				logger.info("退款 微信回调返回商户订单号：" + map.get("out_trade_no"));
				// 支付成功 修改订单状态 通知微信成功回调
				EntityWrapper<Orderinfo> ew = new EntityWrapper<>();
				ew.eq("order_info_id", outTradeNo);
				Orderinfo order = new Orderinfo();
				order = order.selectOne(ew);
//				order.setStatus(Const.OrderStatusEnum.REFUND_SUCCESS.getCode());
				if (order != null) {
					order.setStatus(4);
					boolean sqlRow = order.updateById();
					if (sqlRow) {
						User user = new User();
						user.setId(order.getUserId());
						user = user.selectById();

						Log log = new Log();
						log.setLogId(Hutool.getId());
						log.setAddtime(Hutool.parseDateToString());
						log.setLogDesc("微信退款");
						Double money = order.getTotalMoney() - Double.parseDouble(order.getCouponMoney());
						log.setLogName(user.getName() + "\n微信退款:" + money + "元");
						log.setLogType(1);
						log.setMoneys(money + "");
						log.setOrderId(outTradeNo);
						log.setUserId(order.getUserId());
						log.insert();
						logger.info("退款 微信回调 更改订单状态成功");
					}
				} else {
					logger.info("退款 微信回调返回是否退款成功：否");
				}
			} else {
				// 获得 返回的商户订单号
				String passMap = AESUtil.decryptData(map.get("req_info"));
				// 拿到解密信息
				map = XMLUtil.doXMLParse(passMap);
				// 拿到解密后的订单号
				String outTradeNo = map.get("out_trade_no");
				// 更改 状态为取消
				EntityWrapper<Orderinfo> ew = new EntityWrapper<>();
				ew.eq("order_info_id", outTradeNo);
				Orderinfo order = new Orderinfo();
				order = order.selectOne(ew);
//				order.setStatus(Const.OrderStatusEnum.REFUND_ERROR.getCode());
				boolean sqlRow = order.updateById();
				if (sqlRow) {
					logger.info("退款 微信回调返回是否退款成功：否");
				}
			}

			// 给微信服务器返回 成功标示 否则会一直询问 咱们服务器 是否回调成功
			PrintWriter writer = response.getWriter();
			// 封装 返回值
			StringBuffer buffer = new StringBuffer();
			buffer.append("<xml>");
			buffer.append("<return_code><![CDATA[SUCCESS]]></return_code>");
			buffer.append("<return_msg><![CDATA[OK]]></return_msg>");
			buffer.append("</xml>");
			// 返回
			writer.print(buffer.toString());
			System.out.println(buffer.toString());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String args[]) {
		String notifyStr = XMLUtil.setXML("SUCCESS", "");
		System.out.println(notifyStr);
	}
}
